package com.xneure.code;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
import com.xneure.code.msg.MessageListener;
import com.xneure.code.msg.MsgManage;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.PackageUtil;
import com.xneure.utils.SpringUtil;
import com.xneure.utils.bean.ClassFilter;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

@Component
public class InheritedBeanConvert implements InstantiationAwareBeanPostProcessor{
	static Map<Class<?>,Class<?>> beans = new HashMap<>();
	static Map<Integer,Method> methods = new ConcurrentSkipListMap<>();

	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass,String beanName) throws BeansException{
		try{
			if(beans.containsKey(beanClass)){
				return ObjectUtil.objectProxy(beanClass,new MethodInterceptor(){
					@Override
					public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws Throwable{
						Object _bean = SpringUtil.getBean(beans.get(ObjectUtil.peelingCGLIB(obj.getClass())));
						Method _method = methods.get(method.hashCode());
						if(null == _method){
							Class<?>[] type = null;
							if(null != args && args.length > 0){
								type = new Class<?>[args.length];
								for(int i = 0;i < args.length;i++){
									type[i] = args[i].getClass();
								}
							}
							_method = ObjectUtil.getMethod(ObjectUtil.peelingCGLIB(_bean.getClass()),method.getName(),type);
							if(null == _method){
								return proxy.invokeSuper(obj,args);
							}
							methods.put(method.hashCode(),_method);
						}
						return ObjectUtil.callMethod(_bean,_method,args);
					}
				});
			}
			return null;
		}catch(Exception e){
			return null;
		}
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean,String beanName) throws BeansException{
		return true;
	}

	@Override
	public PropertyValues postProcessPropertyValues(PropertyValues pvs,PropertyDescriptor[] pds,Object bean,String beanName) throws BeansException{
		return pvs;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException{
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException{
		return bean;
	}

	static void proxyListener(){
		MsgManage.getSysMsgManage().registerListen(AutoProxy.class,new MessageListener<AutoProxy>(){
			@Override
			public void handler(AutoProxy msg,Enum<?> action){
				PackageUtil.getClassList(msg.getPackagePath(),new ClassFilter(){
					@Override
					public Class<?> filter(Class<?> c){
						TargetProxy annotation = c.getAnnotation(TargetProxy.class);
						if(annotation != null){
							InheritedBeanConvert.beans.put(annotation.value(),c);
							return c;
						}
						return null;
					}
				});
			}
		});
	}
}
